﻿

namespace SMEsCustomer360Degree.Controllers
{
    using Common.Cache;
    using Common.Contract;
    using Common.Contract.Authentication;
    using Common.Contract.Authentication.Record;
    using Common.Contract.Authentication.Request;
    using Common.Service;
    using Common.Type;
    using Common.Web.Share;
    using Common.Util;
    using SMEsCustomer360Degree.Controllers.core;
    using SMEsCustomer360Degree.Core.Configuration;
    using SMEsCustomer360Degree.Models.Interface;
    using SMEsCustomer360Degree.Providers;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using SMEsCustomer360Degree.Models.ViewModels;
    using Common.Contract.SystemConfig;
    using Common.Contract.SystemConfig.Request;
    using Common.Contract.SystemConfig.Record;
    public class ControllerBase : Controller
    {
        public ControllerBase()
        {
            if (this.Provider == null) this.Provider = new ProviderFactory();
        }
        protected List<string> ALLOW_PAGES = new List<string>() { "/HOME/ERROR/", "/HOME/DATAFIX/", "/ACCOUNT/LOGOUT/" };
        public IProviderFactory Provider { get; private set; }

        #region Load Controller
        protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
        {
            string lang = null;
            HttpCookie langCookie = Request.Cookies["currentLang"];
            if (langCookie != null)
            {
                lang = langCookie.Value;
            }
            else
            {
                var userLanguage = Request.UserLanguages;
                var userLang = userLanguage != null ? userLanguage[0] : "";
                if (userLang != "")
                {
                    lang = userLang;
                }
                else
                {
                    lang = SiteLanguages.GetDefaultLanguage();
                }
            }

            new SiteLanguages().SetLanguage(lang);

            return base.BeginExecuteCore(callback, state);
        }
        #endregion

        #region Menu
        private List<TreeViewNode> menuNodes;
        public Guid ApplicationKey { get { return SystemConfiguration.ApplicationKey; } }

        public string AccessRoleIdentifier
        {
            get
            {
                return CacheFactory.MemCache.GetFromCache<string>(CACHING_NAME.ROLE_ACCESS_IDENTIFIER, () =>
                {
                    var header = new RequestHeaderRecord
                    {
                        ApplicationKey = this.ApplicationKey,
                        CallerName = "Authentication.Web.Controller.ControllerBase.AccessRoleIdentifier"
                    };

                    using (ServiceClient<IConfiguration> serviceClient = new ServiceClient<IConfiguration>())
                    {
                        RetrieveDictionaryRequest request = new RetrieveDictionaryRequest
                        {
                            Header = header,
                            Key = SystemConfiguration.RoleLinkAccessKey
                        };
                        var objectResponse = serviceClient.Proxy.RetrieveDictionary(request);


                        if (objectResponse.IsSuccess)
                        {
                            return objectResponse.Record.Value;
                        }
                        else
                        {
                            DictionaryRecord record = new DictionaryRecord { ApplicationKey = SystemConfiguration.ApplicationKey, Key = SystemConfiguration.RoleLinkAccessKey, Value = SystemConfiguration.RoleLinkAccess };
                            AddDictionaryRequest request3 = new AddDictionaryRequest
                            {
                                Header = header,
                                Record = record
                            };
                            var response = serviceClient.Proxy.AddDictionary(request3);
                        }
                    }
                    return SystemConfiguration.RoleLinkAccess;
                }, SystemConfiguration.DefaultCacheTime);
            }
        }

        protected List<TreeViewNode> MenuNodes
        {
            get
            {
                if (menuNodes == null)
                {
                    menuNodes = GetMenuNodes(this.CurrentUser);
                }
                return menuNodes;
            }
        }

        public string CurrentURL
        {
            get
            {
                var urlLocal = Request.Url.LocalPath.ToLower();
                if (!string.IsNullOrEmpty(urlLocal) && !urlLocal.EndsWith("/")) urlLocal = urlLocal.ToLower() + "/";
                else if (urlLocal == "/") urlLocal = string.Empty;
                return urlLocal;
            }
        }


        public Dictionary<string, UserRoleRecord> CurrentRules
        {
            get
            {
                if (CurrentUser.IsNullOrWhiteSpace()) return null;
                string groupId = CurrentUserRecord.GroupIdentifier;
                string userId = CurrentUserRecord.UserName;
                Dictionary<string, UserRoleRecord> result = new Dictionary<string, UserRoleRecord>();
                return CacheFactory.MemCache.GetFromCache<Dictionary<string, UserRoleRecord>>(string.Format("[{0}].[{1}]", CACHING_NAME.CURRENT_USER_RECORD_RULES_DICT, userId), () =>
                {
                    List<ObjectRecord> menuitems = null;
                    Dictionary<string, UserRoleRecord> userDicts = new Dictionary<string, UserRoleRecord>();
                    Dictionary<string, GroupRoleRecord> groupDicts = new Dictionary<string, GroupRoleRecord>();

                    using (ServiceClient<IAuthentication> serviceClient = new ServiceClient<IAuthentication>())
                    {
                        RetrieveObjectsRequest request = new RetrieveObjectsRequest
                        {
                            Header = new RequestHeaderRecord
                            {
                                ApplicationKey = this.ApplicationKey,
                                CallerName = "Authentication.Web.Controller.ControllerBase.CurrentRules"
                            }
                        };
                        var objectResponse = serviceClient.Proxy.RetrieveObjects(request);
                        if (objectResponse.IsSuccess)
                        {
                            menuitems = objectResponse.Records as List<ObjectRecord>;
                        }

                        if (menuitems != null)
                        {
                            menuitems = menuitems.OrderBy(x => x.ObjectIdentifier)/*OrderBy(x => x.OLEVEL).ThenBy(y => y.ORDER_ID).ThenBy(z => z.ID)*/
                                                 .RecursivelyData("ObjectIdentifier", "ParentIdentifier", "ObjectName").ToList();
                        }


                        if (userId != SystemConfiguration.SUPPER_ADMIN)
                        {
                            // Group rule
                            RetrieveGroupRolesRequest requestGroupRule = new RetrieveGroupRolesRequest
                            {
                                Header = new RequestHeaderRecord
                                {
                                    ApplicationKey = this.ApplicationKey,
                                    CallerName = "Authentication.Web.Controller.ControllerBase.CurrentRules"
                                },
                                GroupIdentifier = groupId
                            };
                            var groupRulesResponse = serviceClient.Proxy.RetrieveGroupRoles(requestGroupRule);
                            if (groupRulesResponse.IsSuccess && groupRulesResponse.Records != null)
                            {
                                foreach (GroupRoleRecord obj in groupRulesResponse.Records)
                                {
                                    var key = obj.GroupIdentifier + "$" + obj.ObjectIdentifier;
                                    if (!groupDicts.ContainsKey(key)) groupDicts.Add(key, obj);
                                }
                            }

                            // User rule
                            RetrieveUserRolesRequest requestUserRule = new RetrieveUserRolesRequest
                            {
                                Header = new RequestHeaderRecord
                                {
                                    ApplicationKey = this.ApplicationKey,
                                    CallerName = "Authentication.Web.Controller.ControllerBase.CurrentRules"
                                },
                                UserName = userId
                            };
                            var userRulesResponse = serviceClient.Proxy.RetrieveUserRoles(requestUserRule);

                            if (userRulesResponse.IsSuccess && userRulesResponse.Records != null)
                            {
                                foreach (UserRoleRecord obj in userRulesResponse.Records)
                                {
                                    var key = obj.UserName + "#" + obj.ObjectIdentifier;
                                    if (!userDicts.ContainsKey(key)) userDicts.Add(key, obj);
                                }
                            }
                        }


                        if (menuitems != null)
                        {
                            foreach (var mitem in menuitems)
                            {
                                if (userId == SystemConfiguration.SUPPER_ADMIN)
                                {
                                    UserRoleRecord ruleAll = new UserRoleRecord
                                    {
                                        ApplicationKey = mitem.ApplicationKey,
                                        UserName = userId,
                                        ObjectIdentifier = mitem.ObjectIdentifier,
                                        Object = mitem,
                                        Active = true
                                    };
                                    result.Add(mitem.ObjectIdentifier, ruleAll);
                                    continue;
                                }

                                string keyGroup = groupId + "$" + mitem.ObjectIdentifier;
                                string keyUser = userId + "#" + mitem.ObjectIdentifier;
                                if (userDicts.ContainsKey(keyUser))
                                {
                                    result.Add(mitem.ObjectIdentifier, userDicts[keyUser]);
                                }
                                else if (groupDicts.ContainsKey(keyGroup))
                                {
                                    GroupRoleRecord group = groupDicts[keyGroup];
                                    UserRoleRecord ruleGroup = new UserRoleRecord
                                    {
                                        ApplicationKey = mitem.ApplicationKey,
                                        UserName = userId,
                                        ObjectIdentifier = mitem.ObjectIdentifier,
                                        Object = mitem,
                                        RoleIdentifier = group.RoleIdentifier,
                                        Active = true
                                    };
                                    result.Add(mitem.ObjectIdentifier, ruleGroup);
                                }
                            }
                        }
                    }
                    return result;
                }
                , SystemConfiguration.DefaultCacheTime);
            }
        }



        #endregion

        #region User Properties
        public string CurrentUser
        {
            get
            {
                //return "admin";
                return Membership.CurrentUser;
            }
        }

        public UserRecord CurrentUserRecord
        {
            get
            {
                if (HttpContext.Items[HTTP_CONTEXT.CURRENT_USER_RECORD] == null)
                {
                    using (ServiceClient<IAuthentication> serviceClient = new ServiceClient<IAuthentication>())
                    {
                        RetrieveUserByUserNameRequest request = new RetrieveUserByUserNameRequest
                        {
                            Header = new RequestHeaderRecord
                            {
                                ApplicationKey = this.ApplicationKey,
                                CallerName = "SMEsCustomer360Degree.Controllers.ControllerBase.CurrentUserRecord"
                            },
                            UserName = CurrentUser
                        };
                        var objectResponse = serviceClient.Proxy.RetrieveUserByUserName(request);
                        var record = new UserRecord();
                        record = objectResponse.Record;
                        if (objectResponse.Record == null)
                        {
                            record = new UserRecord
                            {
                                UserName = "daonp",
                                ContractType = "Chuyen vien II",
                                Dao = "3309",
                                Branch = "Sai Gon",
                                Zone = "04",
                                StartWorkingDate = DateTime.Now.Date.ToShortDateString()
                            };
                        }
                        HttpContext.Items[HTTP_CONTEXT.CURRENT_USER_RECORD] = record;
                    }
                }
                return HttpContext.Items[HTTP_CONTEXT.CURRENT_USER_RECORD] as UserRecord;
            }
        }

        #endregion

        #region Helper Functions

        protected List<TreeViewNode> GetMenuNodes()
        {
            var result = CacheFactory.MemCache.GetFromCache<List<TreeViewNode>>(string.Format(CACHING_NAME.CURRENT_MENU_HEADER), () =>
            {
                var nodes = new List<TreeViewNode>();
                nodes = SystemConfiguration.ListMenuHeader.Select(x => new TreeViewNode
                {
                    Name = x.ObjectName,
                    Url = x.ObjectUrl
                }).ToList();
                return nodes;
            });

            return result;
        }

        protected List<TreeViewNode> GetMenuNodes(string user)
        {
            //Get object with the rules
            IEnumerable<ObjectRecord> objectsSub = null;
            using (ServiceClient<IAuthentication> serviceClient = new ServiceClient<IAuthentication>())
            {
                RetrieveObjectsRequest request = new RetrieveObjectsRequest
                {
                    Header = new RequestHeaderRecord
                    {
                        ApplicationKey = SystemConfiguration.ApplicationKey,
                        CallerName = "Authentication.Web.Controller.ControllerBase.GetMenuNodes"
                    },
                    Language = SiteLanguages.GetCurrentLanguage()
                };
                var objectResponse = serviceClient.Proxy.RetrieveObjects(request);
                objectsSub = objectResponse.Records;
            }

            var ruleDicts = this.CurrentRules;
            if (objectsSub != null && user != SystemConfiguration.SUPPER_ADMIN)
                objectsSub = objectsSub.Where(x => (ruleDicts.ContainsKey(x.ObjectIdentifier) && ruleDicts[x.ObjectIdentifier].Active == true && ruleDicts[x.ObjectIdentifier].RoleIdentifier == this.AccessRoleIdentifier)).ToList();


            if (objectsSub == null) return null;
            objectsSub = objectsSub.OrderByDescending(x => x.ObjectIdentifier).ToList();


            //Bill to Dictionary
            Dictionary<string, TreeViewNode> dict = new Dictionary<string, TreeViewNode>();
            var nodes = new List<TreeViewNode>();
            bool access = false;//Authentication values
            foreach (var obj in objectsSub)
            {
                if (user == SystemConfiguration.SUPPER_ADMIN ||
                    (obj.ObjectUrl != null && CurrentURL.ToUpper().Contains(obj.ObjectUrl.ToUpper())) ||
                    ALLOW_PAGES.Contains(CurrentURL)) access = true;
                if (obj.Olvel == 1)
                {
                    var node = new TreeViewNode
                    {
                        Name = obj.ObjectIdentifier,
                        Value = obj.ObjectName,
                        Url = obj.ObjectUrl,
                        CssIcon = obj.ObjectIcon,
                        Controller = obj.ObjectController,
                        Action = obj.ObjectAction,
                        IdCss = obj.IdCss
                    };
                    if (!dict.ContainsKey(node.Name)) dict.Add(node.Name, node);
                }

            }
            if (string.IsNullOrEmpty(CurrentURL)) access = true;

            //Authentication on Menu system
            //if (!access)
            //{
            //    //Redirect to home if can not access
            //    HttpContext.Response.Redirect("~/");
            //    return null;
            //}

            /*if (!CurrentURL.ToUpper().Contains("/ACCOUNT/CHANGEPASSWORD") && sysService.CheckChangePassword(paramsv.CURRENT_USER.USER_NAME, paramsv.CURRENT_USER.PASS))
            {
                //Redirect to home if can not access
                HttpContext.Response.Redirect("~/account/changepassword");
                return null;
            }*/

            //bill to the tree
            foreach (var obj in objectsSub)
            {
                if (obj.IsSubstitution == true) continue;
                if (string.IsNullOrEmpty(obj.ParentIdentifier) || (!dict.ContainsKey(obj.ParentIdentifier)))
                {
                    if (dict.ContainsKey(obj.ObjectIdentifier))
                    {
                        var node = dict[obj.ObjectIdentifier];
                        nodes.Add(node);
                    }
                }
                else
                {
                    var subNode = dict[obj.ParentIdentifier];
                    subNode.Nodes.Add(dict[obj.ObjectIdentifier]);
                }
            }
            return nodes;
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            if (filterContext.HttpContext.Request.HttpMethod != "POST"
                && !CurrentURL.IsNullOrWhiteSpace() && CurrentURL != "/" && !ALLOW_PAGES.Any(x => CurrentURL.ToUpper().Contains(x))
                && !CurrentUser.IsNullOrWhiteSpace() && CurrentUser != SystemConfiguration.SUPPER_ADMIN)
            {
                var url = filterContext.HttpContext.Request.RawUrl.ToLower();// ====> /admin/manage
                //var menuAllow = this.CurrentRules.Where(x => !x.Value.Object.ObjectUrl.IsNullOrWhiteSpace()).Select(x => x.Value.Object.ObjectUrl.EndsWith("/") ? x.Value.Object.ObjectUrl.ToLower() : x.Value.Object.ObjectUrl.ToLower() + "/").ToList();

                //var Active = menuAllow.Any(x => CurrentURL.Contains(x));
                //if (!Active) HttpContext.Response.Redirect("/", true);
            }
        }


        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            string actionName = filterContext.ActionDescriptor.ActionName;
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            var vm = filterContext.Controller.ViewData.Model as IViewModel;
            var modelFull = string.Format("{0}.{1}", controllerName, actionName);
            if (vm != null && !vm.Message.IsNullOrWhiteSpace())
            {
                ModelState.AddModelError(modelFull, vm.Message);
            }
            base.OnActionExecuted(filterContext);
        }

        #endregion
    }
}
